package com.pnnd.stream;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.nio.ByteBuffer;

/**
 * 连续的内存页空间
 * 内存管理的最小单位，
 */
public interface MemorySegment {

    /**
     * @return 内存段结束地址
     */
    long end();

    /**
     * @return 内存段起始地值
     */
    long start();

    /**
     * 物理内存页个数，
     * 一个内存段通常由若干个连续的内存页构成
     * @return 个数
     */
    int physicsPageNum();

    long offset();

    /**
     * 释放当前资源
     */
    void free();

    /**
     *
     * @return 是否包含更多资源
     */
    boolean hasMore();

    /**
     * 预判目标大小的数据是否能写进去，
     * 同一条数据不建议跨段存储
     * @param size 要写入的内存大小
     * @return 是否能写入
     */
    boolean canWrote(int size);

    int size();

    boolean isFreed();

    boolean isOffHeap();

    byte[] getArray();

    /**
     * Wraps the chunk of the underlying memory located between <tt>offset</tt> and
     * <tt>length</tt> in a NIO ByteBuffer. The ByteBuffer has the full segment as capacity
     * and the offset and length parameters set the buffers position and limit.
     *
     * @param offset The offset in the memory segment.
     * @param length The number of bytes to be wrapped as a buffer.
     *
     * @return A <tt>ByteBuffer</tt> backed by the specified portion of the memory segment.
     * @throws IndexOutOfBoundsException Thrown, if offset is negative or larger than the memory segment size,
     *                                   or if the offset plus the length is larger than the segment size.
     */
    ByteBuffer wrap(int offset, int length);

    /**
     * 获取当前内存段的持有者，由于此内存操作不是线程安全的，只能由一个对象来操作
     * @return
     */
    Object getOwner();

    /**
     * Reads the byte at the given position.
     *
     * @param index The position from which the byte will be read
     * @return The byte at the given position.
     *
     * @throws IndexOutOfBoundsException Thrown, if the index is negative, or larger or equal to the size of
     *                                   the memory segment.
     */
    byte get(int index);

    /**
     * Writes the given byte into this buffer at the given position.
     *
     * @param index The index at which the byte will be written.
     * @param b The byte value to be written.
     *
     * @throws IndexOutOfBoundsException Thrown, if the index is negative, or larger or equal to the size of
     *                                   the memory segment.
     */
    void put(int index, byte b);

    /**
     * Bulk get method. Copies dst.length memory from the specified position to
     * the destination memory.
     *
     * @param index The position at which the first byte will be read.
     * @param dst The memory into which the memory will be copied.
     *
     * @throws IndexOutOfBoundsException Thrown, if the index is negative, or too large that the data between the
     *                                   index and the memory segment end is not enough to fill the destination array.
     */
    void get(int index, byte[] dst);

    /**
     * Bulk put method. Copies src.length memory from the source memory into the
     * memory segment beginning at the specified position.
     *
     * @param index The index in the memory segment array, where the data is put.
     * @param src The source array to copy the data from.
     *
     * @throws IndexOutOfBoundsException Thrown, if the index is negative, or too large such that the array
     *                                   size exceed the amount of memory between the index and the memory
     *                                   segment's end.
     */
    void put(int index, byte[] src);

    /**
     * Bulk get method. Copies length memory from the specified position to the
     * destination memory, beginning at the given offset.
     *
     * @param index The position at which the first byte will be read.
     * @param dst The memory into which the memory will be copied.
     * @param offset The copying offset in the destination memory.
     * @param length The number of bytes to be copied.
     *
     * @throws IndexOutOfBoundsException Thrown, if the index is negative, or too large that the requested number of
     *                                   bytes exceed the amount of memory between the index and the memory
     *                                   segment's end.
     */
    void get(int index, byte[] dst, int offset, int length);

    /**
     * Bulk put method. Copies length memory starting at position offset from
     * the source memory into the memory segment starting at the specified
     * index.
     *
     * @param index The position in the memory segment array, where the data is put.
     * @param src The source array to copy the data from.
     * @param offset The offset in the source array where the copying is started.
     * @param length The number of bytes to copy.
     *
     * @throws IndexOutOfBoundsException Thrown, if the index is negative, or too large such that the array
     *                                   portion to copy exceed the amount of memory between the index and the memory
     *                                   segment's end.
     */
    void put(int index, byte[] src, int offset, int length);

    /**
     * Reads one byte at the given position and returns its boolean
     * representation.
     *
     * @param index The position from which the memory will be read.
     * @return The boolean value at the given position.
     *
     * @throws IndexOutOfBoundsException Thrown, if the index is negative, or larger than the segment
     *                                   size minus 1.
     */
    boolean getBoolean(int index);

    /**
     * Writes one byte containing the byte value into this buffer at the given
     * position.
     *
     * @param index The position at which the memory will be written.
     * @param value The char value to be written.
     *
     * @throws IndexOutOfBoundsException Thrown, if the index is negative, or larger than the segment
     *                                   size minus 1.
     */
    void putBoolean(int index, boolean value);

    @SuppressWarnings("restriction")
    char getChar(int index);

    char getCharLittleEndian(int index);

    char getCharBigEndian(int index);

    @SuppressWarnings("restriction")
    void putChar(int index, char value);

    void putCharLittleEndian(int index, char value);

    void putCharBigEndian(int index, char value);

    short getShort(int index);

    short getShortLittleEndian(int index);

    short getShortBigEndian(int index);

    void putShort(int index, short value);

    void putShortLittleEndian(int index, short value);

    void putShortBigEndian(int index, short value);

    int getInt(int index);

    int getIntLittleEndian(int index);

    int getIntBigEndian(int index);

    void putInt(int index, int value);

    void putIntLittleEndian(int index, int value);

    void putIntBigEndian(int index, int value);

    long getLong(int index);

    long getLongLittleEndian(int index);

    long getLongBigEndian(int index);

    void putLong(int index, long value);

    void putLongLittleEndian(int index, long value);

    void putLongBigEndian(int index, long value);

    float getFloat(int index);

    float getFloatLittleEndian(int index);

    float getFloatBigEndian(int index);

    void putFloat(int index, float value);

    void putFloatLittleEndian(int index, float value);

    void putFloatBigEndian(int index, float value);

    double getDouble(int index);

    double getDoubleLittleEndian(int index);

    double getDoubleBigEndian(int index);

    void putDouble(int index, double value);

    void putDoubleLittleEndian(int index, double value);

    void putDoubleBigEndian(int index, double value);

    void get(DataOutput out, int offset, int length) throws IOException;

    /**
     * Bulk put method. Copies length memory from the given DataInput to the
     * memory starting at position offset.
     *
     * @param in The DataInput to get the data from.
     * @param offset The position in the memory segment to copy the chunk to.
     * @param length The number of bytes to get.
     *
     * @throws IOException Thrown, if the DataInput encountered a problem upon reading,
     *                     such as an End-Of-File.
     */
    void put(DataInput in, int offset, int length) throws IOException;

    /**
     * Bulk get method. Copies {@code numBytes} bytes from this memory segment, starting at position
     * {@code offset} to the target {@code ByteBuffer}. The bytes will be put into the target buffer
     * starting at the buffer's current position. If this method attempts to write more bytes than
     * the target byte buffer has remaining (with respect to {@link ByteBuffer#remaining()}),
     * this method will cause a {@link java.nio.BufferOverflowException}.
     *
     * @param offset The position where the bytes are started to be read from in this memory segment.
     * @param target The ByteBuffer to copy the bytes to.
     * @param numBytes The number of bytes to copy.
     *
     * @throws IndexOutOfBoundsException If the offset is invalid, or this segment does not
     *           contain the given number of bytes (starting from offset), or the target byte buffer does
     *           not have enough space for the bytes.
     */
    void get(int offset, ByteBuffer target, int numBytes);

    /**
     * Bulk put method. Copies {@code numBytes} bytes from the given {@code ByteBuffer}, into
     * this memory segment. The bytes will be read from the target buffer
     * starting at the buffer's current position, and will be written to this memory segment starting
     * at {@code offset}.
     * If this method attempts to read more bytes than
     * the target byte buffer has remaining (with respect to {@link ByteBuffer#remaining()}),
     * this method will cause a {@link java.nio.BufferUnderflowException}.
     *
     * @param offset The position where the bytes are started to be written to in this memory segment.
     * @param source The ByteBuffer to copy the bytes from.
     * @param numBytes The number of bytes to copy.
     *
     * @throws IndexOutOfBoundsException If the offset is invalid, or the source buffer does not
     *           contain the given number of bytes, or this segment does
     *           not have enough space for the bytes (counting from offset).
     */
    void put(int offset, ByteBuffer source, int numBytes);

    void copyTo(int offset, AbstractMemorySegment target, int targetOffset, int numBytes);

    void copyToUnsafe(int offset, Object target, int targetPointer, int numBytes);

    void copyFromUnsafe(int offset, Object source, int sourcePointer, int numBytes);
}
